import json
import random
import time
from pyzbar import pyzbar
import requests
from PIL import Image
import io
import qrcode_terminal
import redis

def login_by_QR():
    # jd login by QR code
    try:
        print('+++++++++++++++++++++++++++++++++++++++++++++++++++++++')
        print('{0} > 请打开京东手机客户端，准备扫码登陆:'.format(time.ctime()))

        urls = (
            'https://passport.jd.com/new/login.aspx',
            'https://qr.m.jd.com/show',
            'https://qr.m.jd.com/check',
            'https://passport.jd.com/uc/qrCodeTicketValidation'
        )
        sess = requests.Session()
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
            'ContentType': 'text/html; charset=utf-8',
            'Accept-Encoding': 'gzip, deflate, sdch',
            'Accept-Language': 'zh-CN,zh;q=0.8',
            'Connection': 'keep-alive',
        }
        cookies = {}
        # step 1: open login page
        resp = sess.get(
            urls[0],
            headers=headers
        )
        if resp.status_code != requests.codes.OK:
            print('获取登录页失败: %u' % resp.status_code)
            return False

        # save cookies
        for k, v in list(resp.cookies.items()):
            cookies[k] = v

        # step 2: get QR image
        resp = sess.get(
            urls[1],
            headers=headers,
            cookies=cookies,
            params={
                'appid': 133,
                'size': 147,
                't': (int)(time.time() * 1000)
            }
        )
        if resp.status_code != requests.codes.OK:
            print('获取二维码失败: %u' % resp.status_code)
            return False

        # save cookies
        for k, v in list(resp.cookies.items()):
            cookies[k] = v

        # save QR code
        raw_data = resp.content
        decode_result = pyzbar.decode(Image.open(io.BytesIO(raw_data)))
        qr_img = decode_result[0].data.decode()
        print('+++++++++++++++++++++++++++++++++++++++++++++++++++++++')
        print(qr_img)
        qrcode_terminal.draw(qr_img)

        # step 3: check scan result
        ## mush have
        headers['Host'] = 'qr.m.jd.com'
        headers['Referer'] = 'https://passport.jd.com/new/login.aspx'

        # check if QR code scanned
        qr_ticket = None
        retry_times = 100
        while retry_times:
            retry_times -= 1
            resp = sess.get(
                urls[2],
                headers=headers,
                cookies=cookies,
                params={
                    'callback': 'jQuery%u' % random.randint(100000, 999999),
                    'appid': 133,
                    'token': cookies['wlfstk_smdl'],
                    '_': (int)(time.time() * 1000)
                }
            )

            if resp.status_code != requests.codes.OK:
                continue

            n1 = resp.text.find('(')
            n2 = resp.text.find(')')
            rs = json.loads(resp.text[n1 + 1:n2])

            if rs['code'] == 200:
                print('{} : {}'.format(rs['code'], rs['ticket']))
                qr_ticket = rs['ticket']
                break
            else:
                print('{} : {}'.format(rs['code'], rs['msg']))
                time.sleep(3)

        if not qr_ticket:
            print('二维码登陆失败')
            return False

        # step 4: validate scan result
        ## must have
        headers['Host'] = 'passport.jd.com'
        headers['Referer'] = 'https://passport.jd.com/uc/login?ltype=logout'
        resp = sess.get(
            urls[3],
            headers=headers,
            cookies=cookies,
            params={'t': qr_ticket},
        )
        if resp.status_code != requests.codes.OK:
            print('二维码登陆校验失败: %u' % resp.status_code)
            print(resp.content)
            return False

        ## 京东有时候会认为当前登录有危险，需要手动验证
        ## url: https://safe.jd.com/dangerousVerify/index.action?username=...
        res = json.loads(resp.text)
        if not resp.headers.get('P3P'):
            if 'url' in res:
                print('需要手动安全验证: {0}'.format(res['url']))
                return False
            else:
                print(res)
                print('登陆失败!!')
                return False

        ## login succeed
        headers['P3P'] = resp.headers.get('P3P')
        for k, v in list(resp.cookies.items()):
            cookies[k] = v

        conn = redis.Redis()
        key = cookies['pin']
        value = ";".join("%s=%s" % (k, v) for k, v in cookies.items())
        conn.hset("jd_cookie", key, value)

        # with open('cookie', 'wb') as f:
        #     pickle.dump(self.cookies, f)

        # conn = redis.Redis()

        print('登陆成功')
        return True

    except Exception as e:
        print('Exp:', e)
        raise

    return False

if __name__ == "__main__":
    login_by_QR()